package com.syh.jn.scm.service.impl.supplier.stock;

import cn.redscarf.commons.lock.Lock;
import cn.redscarf.commons.lock.LockParam;
import cn.redscarf.commons.util.other.ExtAssert;
import cn.redscarf.commons.spring.SpringContextUtils;
import cn.redscarf.commons.wrapper.Restrictions;
import cn.redscarf.commons.wrapper.Wrapper;
import com.alibaba.dubbo.config.annotation.Service;
import com.syh.core.ddd.event.annotation.DomainEventHandle;
import com.syh.core.ddd.infrastructure.repository.AggregateRepository;
import com.syh.core.ddd.service.AbstractServiceImpl;
import com.syh.jn.scm.domain.supplier.entity.base.Storehouse;
import com.syh.jn.scm.domain.supplier.entity.base.goods.Goods;
import com.syh.jn.scm.domain.supplier.entity.stock.*;
import com.syh.jn.scm.domain.supplier.event.*;
import com.syh.jn.scm.domain.supplier.repository.base.StorehouseReadRepository;
import com.syh.jn.scm.domain.supplier.repository.base.goods.GoodsRepository;
import com.syh.jn.scm.domain.supplier.repository.purchase.PurchaseOrderRepository;
import com.syh.jn.scm.domain.supplier.repository.purchase.PurchaseReturnOrderRepository;
import com.syh.jn.scm.domain.supplier.repository.stock.StockGoodsRepository;
import com.syh.jn.scm.domain.supplier.repository.stock.StockOtherInBillRepository;
import com.syh.jn.scm.dto.supplier.stock.StockBeginGoodsSto;
import com.syh.jn.scm.dto.supplier.stock.StockGoodsVo;
import com.syh.jn.scm.exception.BusinessException;
import com.syh.jn.scm.service.api.supplier.stock.StockGoodsService;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * 库存管理
 */
@Service
@Transactional
public class StockGoodsServiceImpl extends AbstractServiceImpl<Object, Object, StockGoodsVo, StockGoods, Long> implements StockGoodsService {
  @Autowired
  private StockGoodsRepository stockGoodsRepository;
  @Autowired
  private PurchaseOrderRepository purchaseOrderRepository;
  @Autowired
  private PurchaseReturnOrderRepository purchaseReturnOrderRepository;
  @Autowired
  private StockOtherInBillRepository stockOtherInBillRepository;
  @Autowired
  private GoodsRepository goodsRepository;

  @Override
  protected AggregateRepository<StockGoods, Long> getAggregateRepository() {
    return stockGoodsRepository;
  }


  /**
   * 纠正数据使用 根据库存记录纠正库存平均成本、库存余额
   */
  @Override
  public void recalculationStockGoodsAverageCost() {
    stockGoodsRepository.recalculationStockGoodsAverageCost();
  }

  @Override
  public Map<String, Object> statisticalAmount(Wrapper we) {
    return stockGoodsRepository.statisticalAmount(we);
  }

  @Override
  public Map<String, Object> statisticalGoodsType(Wrapper we) {
    return stockGoodsRepository.statisticalGoodsType(we);
  }

  /**
   * 期初设置
   *
   * @param sto
   */
  @Override
  public void beginningSetUp(StockBeginGoodsSto sto) {
    StockGoods stockGoods = stockGoodsRepository.getById(sto.getId());
    if (stockGoods == null) {
      throw new BusinessException("找不到id为" + sto.getId() + "的库存商品!");
    }
    stockGoods.beginningSetUp(sto);
    stockGoodsRepository.update(stockGoods);
  }

  /**
   * 批量设置期初库存
   *
   * @param stos
   */
  @Override
  public void batchBeginningSetUp(List<StockBeginGoodsSto> stos) {
    stos.forEach(sto -> {
      this.beginningSetUp(sto);
    });
  }

  /**
   * 消费者：获取商品添加信息
   *
   * @param goods
   */
  @DomainEventHandle(GoodsEvent.GOODS_SAVE)
  protected void handleGoodsSaveEvent(Goods goods) {
    ExtAssert.notNull(goods, "对象为空");

    StockGoods stockGoods = new StockGoods();
    stockGoods.save(goods);
    //获取所有仓库信息
    StorehouseReadRepository storehouseReadRepository = (StorehouseReadRepository) SpringContextUtils.getBean("storehouseRepositoryImpl");
    List<Storehouse> storehouseList = storehouseReadRepository.getList(Wrapper.build().append(Restrictions.eq("businessEntityId", goods.getBusinessEntityId())));

    //为每一个仓库添加商品
    storehouseList.stream().forEach(storehouse -> {
      stockGoods.setStorehouseId(storehouse.getId());
      stockGoodsRepository.add(stockGoods);
    });
  }

  /**
   * 消费者：获取商品修改信息
   *
   * @param goods
   */
  @DomainEventHandle(GoodsEvent.GOODS_UPDATE)
  protected void handleGoodsUpdateEvent(Goods goods) {
    ExtAssert.notNull(goods, "对象为空");

    Wrapper we = Wrapper.build();
    we.append(Restrictions.eq("goodsId", goods.getId()));
    we.append(Restrictions.eq("businessEntityId", goods.getBusinessEntityId()));
    List<StockGoods> stockGoodsList = stockGoodsRepository.getList(we);

    //修改当前商品的所有库存信息
    stockGoodsList.stream().forEach(stockGoods -> {
      stockGoods.update(goods);
      stockGoodsRepository.update(stockGoods);
    });
  }

  /**
   * 消费者：获取商品删除信息
   *
   * @param goods
   */
  @DomainEventHandle(GoodsEvent.GOODS_DEL)
  protected void handleGoodsDelEvent(Goods goods) {
    ExtAssert.notNull(goods, "对象为空");

    Wrapper we = Wrapper.build();
    we.append(Restrictions.eq("goodsId", goods.getId()));
    we.append(Restrictions.eq("businessEntityId", goods.getBusinessEntityId()));
    List<StockGoods> stockGoodsList = stockGoodsRepository.getList(we);

    //移除当前商品的所有仓库库存
    stockGoodsList.stream().forEach(stockGoods -> {
      stockGoodsRepository.remove(stockGoods);
    });
  }

  /**
   * 监听库存记录变化更新库存
   *
   * @param stockRecord
   */
  @DomainEventHandle({StockRecordEvent.STOCK_RECORD_CREATED})
  @Lock(lockNamePre = "jnscm_supplier_stockRecord")
  protected void handleLogisticsBillDeliveryEvent(@LockParam(filed = "id") StockRecord stockRecord) {
    if (stockRecord.getStorehouseId() == null) {
      throw new BusinessException("库存记录中的仓库ID不能为空");
    }
    //查找出库存相对应的商品
    List<StockRecordItem> items = stockRecord.getItems();
    //计算订单每样商品总数量和平均单价
    for (StockRecordItem item : items) {
      StockGoods stockGoods = this.findCurrentStockGoods(stockRecord.getBusinessEntityId(), stockRecord.getStorehouseId(), item.getGoodsId());
      stockGoods.calculateAverageCost(item);
      stockGoodsRepository.update(stockGoods);
    }
  }

  /**
   * 消费者：获取仓库添加信息
   *
   * @param storehouse
   */
  @DomainEventHandle(StorehouseEvent.STOREHOUSE_CREATED)
  protected void handleStorehouseAddEvent(Storehouse storehouse) {
    ExtAssert.notNull(storehouse, "对象为空");

    StockGoods stockGoods = new StockGoods();
    //获取所有商品信息（商品管理的商品）
    Wrapper we = Wrapper.build().append(Restrictions.eq("businessEntityId", storehouse.getBusinessEntityId()));
    List<Goods> goodsList = goodsRepository.getList(we);
    //为新建仓库添加初始库存
    goodsList.stream().forEach(goods -> {
      stockGoods.save(goods);
      stockGoods.setStorehouseId(storehouse.getId());
      stockGoodsRepository.add(stockGoods);
    });
  }


  /**
   * 消费者：获取仓库删除id信息
   *
   * @param storehouse
   */
  @DomainEventHandle(StorehouseEvent.STOREHOUSE_DEL)
  protected void handleStorehouseDelEvent(Storehouse storehouse) {
    Wrapper we = Wrapper.build();
    we.append(Restrictions.eq("businessEntityId", storehouse.getBusinessEntityId()));
    we.append(Restrictions.eq("storehouseId", storehouse.getId()));
    List<StockGoods> stockGoodsList = stockGoodsRepository.getList(we);

    stockGoodsList.stream().forEach(stockGoods -> {
      stockGoodsRepository.remove(stockGoods);
    });
  }

  /**
   * 根据仓库id获取当前仓库的库存商品信息
   *
   * @param storehouseId
   * @return
   */
  private StockGoods findCurrentStockGoods(Long businessEntityId, Long storehouseId, Long goodsId) {
    //查找出相应仓库的库存商品
    Wrapper we = Wrapper.build();
    we.append(Restrictions.eq("businessEntityId", businessEntityId));
    we.append(Restrictions.eq("storehouseId", storehouseId));
    we.append(Restrictions.eq("goodsId", goodsId));
    return stockGoodsRepository.getOne(we);
  }

  /**
   * 订单商品信息 用于统计订单商品采购数量与平均单价
   */
  @Data
  private class OrderGoodsMessage {
    /**
     * 商品id
     */
    private Long goodsId;
    /**
     * 订单数量
     */
    private BigDecimal quantity = BigDecimal.ZERO;
    /**
     * 平均单价
     */
    private BigDecimal averagePrice = BigDecimal.ZERO;


    public void addGoodsMessage(Long goodsId, BigDecimal quantity, BigDecimal price) {
      if (this.goodsId == null) {
        this.goodsId = goodsId;
      }
      if (!this.goodsId.equals(goodsId)) {
        throw new BusinessException("计算订单平均成本失败，传入商品id与记录的id不一致");
      }
      //如果发货数量不为0 则计算平均价格和统计数量  避免除数为0的情况
      if (quantity.compareTo(BigDecimal.ZERO) != 0) {
        BigDecimal total = this.quantity.multiply(this.averagePrice).add(quantity.multiply(price));
        this.averagePrice = total.divide(this.quantity.add(quantity), 6, BigDecimal.ROUND_HALF_UP);
        this.quantity = this.quantity.add(quantity);
      }
    }

  }
}
